﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using KamLib;

namespace KamLib
{
    public class UilContext : IDisposable
    {

        #region Controllers

        public readonly List<UilController> Controllers = new List<UilController>();

        /// <summary>
        /// Ищет по key уже существующий контроллер, если не находит - создаёт новый
        /// </summary>
        /// <param name="key"> </param>
        /// <returns> </returns>
        public UilController GetController(UilKey key)
        {
            var controller = FindController(key);
            if (controller == null)
            {
                var typeInfo = UilRouteTable.ControllerTypes.Try(key.CTID);
                if (typeInfo == null)
                    throw new ArgumentException("UilContext.GetController: The CTID = '" + key.CTID + "' is not exists", "key");

                Controllers.Add(controller = typeInfo.NewController(this, key));
            }
            return controller;
        }

        /// <summary>
        /// Создаёт контроллер типа controllerType
        /// </summary>
        public UilController NewController(Type controllerType, UilKey key = null)
        {
            var typeInfo = UilRouteTable.ControllerTypesByType.Try(controllerType);
            if (typeInfo == null)
                throw new ArgumentException("The type '" + controllerType.Name + "' is not registred as Controller", "key");

            key = key ?? new UilKey();
            key.CTID = typeInfo.CTID;

            var controller = typeInfo.NewController(this, key);
            Controllers.Add(controller);
            return controller;
        }

        /// <summary>
        /// Создаёт контроллер типа T
        /// </summary>
        /// <param name="key"> </param>
        /// <returns> </returns>
        public UilController New<T>(UilKey key = null) where T : UilController
        {
            return NewController(typeof(T), key);
        }


        public UilController FindController(UilKey key)
        {
            foreach (var controller in Controllers)
            {
                var ckey = controller.Key;
                if (key.CTID == ckey.CTID && key.VTID == ckey.VTID && key.VID == ckey.VID)
                    return controller;
            }
            return null;
        }

        #endregion


        #region View

        public IUilView NewView(UilController controller, string vtid = null)
        {
            var key = controller.Key;
            if (vtid == null && (key == null || key.VTID == null))
                throw new ArgumentNullException("vtid");

            if (vtid == null)
                vtid = key.VTID;
            else
                key.VTID = vtid;

            var viewInfo = UilRouteTable.ViewTypes.Try(vtid);
            if (viewInfo == null)
                throw new ArgumentException("The VTID = '" + vtid + "' is not exists", "vtid");

            var view = viewInfo.NewView(this, key);
            if (view == null)
                throw new Exception("Can't create view by VTID = '" + vtid + "'");

            controller.InitView(view);

            return view;
        }

        #endregion


        #region IDisposable Members

        public void Dispose()
        {
            foreach (var сontroller in Controllers)
            {
                сontroller.Dispose();
            }

            if (_DbConnection != null)
            {
                _DbConnection.Dispose();
                _DbConnection = null;
            }
        }

        #endregion


        #region Db

        public static Func<string, IDbConnection> NewDbConnection_;
        public static string DefaultConnectionStringName;
        public static string DefaultConnectionString;

        public static string GetConnectionString(string connectionStringName)
        {
            var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
            if (connectionStringSettings == null)
                throw new InvalidOperationException("Connection string \"" + connectionStringName + "\" could not be found in the configuration file.");
            return connectionStringSettings.ConnectionString;
        }

        public static IDbConnection NewDbConnection(string connectionString = null)
        {
            connectionString = connectionString ?? DefaultConnectionString
                ?? (DefaultConnectionString = GetConnectionString(DefaultConnectionStringName));
            return connectionString.isfull() ? NewDbConnection_(connectionString) : null;
        }


        private IDbConnection _DbConnection;
        public IDbConnection DbConnection { get { return _DbConnection ?? (_DbConnection = NewDbConnection()); } }

        #endregion


        #region Notifications

        public UilNotification.List Notifications = new UilNotification.List();

        #endregion
    }

    public enum UilNotificationKind { Info, Error, Warning }

    public class UilNotification
    {
        public UilNotificationKind Kind;
        public string Title;
        public string Message;
        public bool? Pinned;
        public int? Width;
        public int? Height;

        public class List : List<UilNotification>
        {
            public UilNotification Add(string Message,
                string Title = null, UilNotificationKind Kind = UilNotificationKind.Info,
                bool? Pinned = null, int? Width = null, int? Height = null
            )
            {
                var ntf = new UilNotification
                {
                    Kind = Kind,
                    Title = Title,
                    Message = Message,
                };

                if (Pinned != null) ntf.Pinned = Pinned.Value;
                if (Width != null) ntf.Width = Width.Value;
                if (Height != null) ntf.Height = Height.Value;


                Add(ntf);
                return ntf;
            }

            public UilNotification AddInfo(string Message, string Title = null, bool? Pinned = null, int? Width = null, int? Height = null)
            {
                return Add(Message, Title, UilNotificationKind.Info, Pinned, Width, Height);
            }

            public UilNotification AddError(string Message, string Title = null, bool? Pinned = null, int? Width = null, int? Height = null)
            {
                return Add(Message, Title, UilNotificationKind.Error, Pinned, Width, Height);
            }

            public UilNotification AddWarning(string Message, string Title = null, bool? Pinned = null, int? Width = null, int? Height = null)
            {
                return Add(Message, Title, UilNotificationKind.Warning, Pinned, Width, Height);
            }
        }

    }

}